/**
 * @file STL_FileSystem.cpp
 * @author Derek Liu (yjkhtddx@sina.com)
 * @brief 
 * @version 0.1
 * @date 2020-09-10
 * 
 * @copyright Copyright Sci-Tech Laboratories (c) 2020
 * 
 */

#include "STL_FileSystem.h"
#include <dirent.h>   //DIR
#include <sys/stat.h> //S_IRWXU
#include "unistd.h"   //access
#include <stdlib.h>   //malloc

namespace STL
{
    std::vector<std::string> fileSystemSplit(std::string str, std::string pattern)
    {
        std::string::size_type pos;
        std::vector<std::string> result;
        str += pattern;
        int size = (int)(str.size());

        for (int i = 0; i < size; i++)
        {
            pos = str.find(pattern, i);
            if (pos < size)
            {
                std::string s = str.substr(i, pos - i);
                result.push_back(s);
                i = (int)(pos + pattern.size() - 1);
            }
        }

        return result;
    }
    //  ---------------------------
    //  ==> File
    //  ---------------------------
    /** 创建目录 */
    int makeDir(std::string dir)
    {
        return mkdir(dir.c_str(), S_IRWXU);
    }
    int makeDirWithParents(std::string fullpath)
    {
        int ret = 0;
        if (fullpath.empty())
        {
            return -1;
        }
        else if (fullpath.at(0) != '/')
        {
            return -1;
        }
        std::vector<std::string> paths = fileSystemSplit(fullpath, "/");
        std::vector<std::string> pathlist;
        for (size_t i = 0; i < paths.size(); i++)
        {
            if (paths.at(i).empty())
            {
                continue;
            }
            else if (paths.at(i) == ".")
            {
                continue;
            }
            else if (paths.at(i) == ".." && pathlist.size() > 0)
            {
                pathlist.pop_back();
                continue;
            }
            else
            {
                pathlist.push_back(paths.at(i));
            }
        }
        std::string path = "";
        for (size_t i = 0; i < pathlist.size(); i++)
        {
            path += "/" + pathlist.at(i);
            if (!checkIsFileExsit(path))
            {
                ret = makeDir(path);
                if (ret != 0)
                    return ret;
            }
        }
        return 0;
    }
    /** 检测文件是否存在 */
    bool checkIsFileExsit(std::string fullpath)
    {
        if (access(fullpath.c_str(), 0) == -1)
        {
            return false;
        }
        return true;
    }
    /** 文件重命名 */
    int renameFile(std::string oldfilename, std::string newfilename)
    {
        int ret = std::rename(oldfilename.c_str(), newfilename.c_str());
        return ret;
    }
    /** 替换文件内容 */
    bool replaceFileString(std::string strInfo, std::string fullPath, long offset /* = 0*/)
    {
        size_t size = strInfo.size();
        if (!(checkIsFileExsit(fullPath)))
        {
            return false;
        }
        if (fullPath.empty() || size == 0)
        {
            return false;
        }
        do
        {
            FILE *fp = fopen(fullPath.c_str(), "wb+");
            if (!fp)
                break;
            fseek(fp, 0, SEEK_END);
            size_t len = ftell(fp);
            if (offset < len)
                fseek(fp, 0, SEEK_SET);
            fwrite(strInfo.c_str(), size, 1, fp);
            fclose(fp);
            return true;
        } while (0);
        return false;
    }
    /** 写字符串到文件 */
    bool writeStringToFile(std::string strInfo, std::string fullPath, bool append /* = false*/)
    {
        size_t size = strInfo.size();
        const char *mode;
        if (append)
            mode = "ab";
        else
            mode = "wb";

        if (fullPath.empty() || size == 0)
        {
            return false;
        }

        do
        {
            FILE *fp = fopen(fullPath.c_str(), mode);
            if (!fp)
                break;
            if (append)
            {
                fseek(fp, 0, SEEK_END);
            }
            fwrite(strInfo.c_str(), size, 1, fp);
            fclose(fp);
            return true;
        } while (0);
        return false;
    }

    /** 读字符串到文件 */
    std::string readStringFromFile(std::string fullpath, long offset /* = 0*/, long len /* = 0*/, long *totle /*= nullptr*/)
    {
        std::string ret = "";
        if (!fullpath.empty())
        {
            unsigned char *buffer = nullptr;
            long size = 0;
            size_t readsize = 0;

            do
            {
                FILE *fp = fopen(fullpath.c_str(), "rb");
                if (!fp)
                    break;
                fseek(fp, 0, SEEK_END);
                size = ftell(fp);
                if (totle)
                    *totle = size;
                if (0 == len)
                    len = size - offset;
                if (size - offset < len)
                    len = size - offset;
                if (0 == len)
                    return ret;
                fseek(fp, offset, SEEK_SET);
                buffer = (unsigned char *)malloc(sizeof(unsigned char) * len);
                if (nullptr == buffer)
                    return ret;
                readsize = fread(buffer, sizeof(unsigned char), len, fp);
                if (0 == readsize)
                    printf("Get data from file %s failed", fullpath.c_str());
                fclose(fp);
            } while (0);
            ret = std::string((const char *)buffer, readsize);
            free(buffer);
        }
        return ret;
    }
    /** 删除文件 */
    bool removeFile(std::string fullPath)
    {
        const char *path = fullPath.c_str();
        if (remove(path) == 0)
            return true;
        else
            return false;
    }
    /** 遍历目录 */
    ///*
    // * File types
    // */
    //#define   DT_UNKNOWN   0          未知
    //#define   DT_FIFO      1          管道或FIFO
    //#define   DT_CHR       2          字符特殊文件
    //#define   DT_DIR       4          目录文件
    //#define   DT_BLK       6          块特殊文件
    //#define   DT_REG       8          普通文件
    //#define   DT_LNK      10          符号连接
    //#define   DT_SOCK     12          套接字
    //#define   DT_WHT      14
    // STL::STLDir listDir(std::string path, int sort /* = 0*/, bool isAsc /* = true*/)
    // {
    //     if (path.substr(path.size() - 1) != "/")
    //         path.append("/");
    //     STL::STLFile file;
    //     int exists;

    //     STL::STLDir ret;
    //     ret.list.clear();
    //     ret.path = path;
    //     ret.isExist = checkIsFileExsit(path);
    //     if (!ret.isExist)
    //         return ret;

    //     DIR *pDir;
    //     struct dirent *ent;
    //     pDir = opendir(path.c_str());
    //     while ((ent = readdir(pDir)) != NULL)
    //     {
    //         if (ent->d_type != DT_REG)
    //             continue; //非普通文件不添加到列表
    //         file.name = ent->d_name;
    //         file.path = path + std::string(ent->d_name);
    //         //        printf("[%d]%s\n",ent->d_type,ent->d_name);
    //         exists = stat(file.path.c_str(), &(file.status));
    //         if (exists < 0)
    //             continue; //文件不存在
    //         //        printf("[stat] size = %lld\n",file.status.st_size);
    //         ret.size += file.status.st_size;
    //         switch (sort)
    //         {
    //         case 1:
    //         {
    //             if (isAsc)
    //             {
    //                 std::list<STL::STLFile>::iterator it = ret.list.begin();
    //                 while (1)
    //                 {
    //                     if (it == ret.list.end())
    //                     {
    //                         ret.list.push_back(file);
    //                         break;
    //                     }
    //                     if (file.status.st_mtimespec.tv_sec < it->status.st_mtimespec.tv_sec)
    //                     {
    //                         ret.list.insert(it, file);
    //                         break;
    //                     }
    //                     else
    //                     {
    //                         ++it;
    //                     }
    //                 }
    //             }
    //             else
    //             {
    //                 std::list<STL::STLFile>::iterator it = ret.list.begin();
    //                 while (1)
    //                 {
    //                     if (it == ret.list.end())
    //                     {
    //                         ret.list.push_back(file);
    //                         break;
    //                     }
    //                     if (file.status.st_mtimespec.tv_sec > it->status.st_mtimespec.tv_sec)
    //                     {
    //                         ret.list.insert(it, file);
    //                         break;
    //                     }
    //                     else
    //                     {
    //                         ++it;
    //                     }
    //                 }
    //             }
    //         }
    //         break;
    //         case 2:
    //         {
    //             if (isAsc)
    //             {
    //                 std::list<STL::STLFile>::iterator it = ret.list.begin();
    //                 while (1)
    //                 {
    //                     if (it == ret.list.end())
    //                     {
    //                         ret.list.push_back(file);
    //                         break;
    //                     }
    //                     if (file.status.st_size < it->status.st_size)
    //                     {
    //                         ret.list.insert(it, file);
    //                         break;
    //                     }
    //                     else
    //                     {
    //                         ++it;
    //                     }
    //                 }
    //             }
    //             else
    //             {
    //                 std::list<STL::STLFile>::iterator it = ret.list.begin();
    //                 while (1)
    //                 {
    //                     if (it == ret.list.end())
    //                     {
    //                         ret.list.push_back(file);
    //                         break;
    //                     }
    //                     if (file.status.st_size > it->status.st_size)
    //                     {
    //                         ret.list.insert(it, file);
    //                         break;
    //                     }
    //                     else
    //                     {
    //                         ++it;
    //                     }
    //                 }
    //             }
    //         }
    //         break;
    //         case 0:
    //         default:
    //             ret.list.push_back(file);
    //             break;
    //         }
    //         //        if(ent->d_type & DT_DIR)
    //         //        {
    //         //            if(strcmp(ent->d_name,".")==0 || strcmp(ent->d_name,"..")==0)
    //         //                continue;
    //         //            listDir(path+"/"+ent->d_name);
    //         //        }else{
    //         //            printf("%s\n",ent->d_name);
    //         //        }
    //     }
    //     return ret;
    // }

} // namespace STL
